package ro.ubbcluj.cs.damate.managers.management;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import ro.ubbcluj.cs.damate.managers.BaseView;
import ro.ubbcluj.cs.damate.managers.administration.UserMapper;
import ro.ubbcluj.cs.damate.persistence.entities.Section;
import ro.ubbcluj.cs.damate.persistence.entities.Team;
import ro.ubbcluj.cs.damate.persistence.entities.User;
import ro.ubbcluj.cs.damate.services.SectionService;
import ro.ubbcluj.cs.damate.services.TeamService;
import ro.ubbcluj.cs.damate.services.UserService;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import java.io.Serializable;
import java.sql.Date;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @author Lorand Fazakas
 */
@Component
@Scope("view")
public class TeamManager extends BaseView implements Serializable {

    @Autowired
    private ManagerView managerView;

    @Autowired
    private TeamService teamService;

    @Autowired
    private SectionService sectionService;

    @Autowired
    private UserService userService;

    private Team newOrModifiedTeamBean;

    private List<Section> selectedSections;
    private List<Section> sections;
    private List<Section> assignableSections;
    private String sectionNameFilter;

    private List<User> users;
    private List<UserMapper> assignableUsers;
    private List<UserMapper> filteredUsers;
    private boolean selectAllBox;

    private List<Team> teams;
    private List<Team> filteredTeams;

    public void save() {
        newOrModifiedTeamBean.setCreationDate(new Date(System.currentTimeMillis()));
        teamService.create(newOrModifiedTeamBean);
        clean();
        managerView.switchPanel(ManagerView.ManagerPanel.LIST_TEAMS.name());
    }

    public void edit(Team team) {
        clean();
        setNewOrModifiedTeamBean(team);
        managerView.switchPanel(ManagerView.ManagerPanel.NEW_TEAM.name());
    }

    public void delete(Team team) {
        teamService.delete(team);
        clean();
    }

    private void clean() {
        this.newOrModifiedTeamBean = null;
        this.selectedSections = null;
        this.sections = null;
        this.assignableSections = null;
        this.sectionNameFilter = null;
        this.users = null;
        this.assignableUsers = null;
        this.filteredUsers = null;
        this.selectAllBox = false;
        this.teams = null;
        this.filteredTeams = null;
    }

    public void openPanel(String panelName) {
        clean();
        managerView.switchPanel(panelName);
    }

    public void removeAssignedSection(Section section) {
        newOrModifiedTeamBean.getSections().remove(section);
    }

    public void removeAllAssignedSections() {
        if (newOrModifiedTeamBean.getSections() != null) {
            newOrModifiedTeamBean.getSections().clear();
        }
    }

    public Team getNewOrModifiedTeamBean() {
        if (newOrModifiedTeamBean == null) {
            this.newOrModifiedTeamBean = new Team();
        }
        return newOrModifiedTeamBean;
    }

    public void setNewOrModifiedTeamBean(Team newOrModifiedTeamBean) {
        this.newOrModifiedTeamBean = newOrModifiedTeamBean;
    }

    public List<Team> getTeams() {
        if (teams == null) {
            this.teams = teamService.findAll();
        }
        return teams;
    }

    public void setTeams(List<Team> teams) {
        this.teams = teams;
    }

    public List<Team> getFilteredTeams() {
        return filteredTeams;
    }

    public void setFilteredTeams(List<Team> filteredTeams) {
        this.filteredTeams = filteredTeams;
    }

    public List<User> getAvailableUsers() {
        return getUsers();
    }

    public List<Section> getSelectedSections() {
        return selectedSections;
    }

    public void setSelectedSections(List<Section> selectedSections) {
        this.selectedSections = selectedSections;
        if (newOrModifiedTeamBean.getSections() == null) {
            newOrModifiedTeamBean.setSections(new ArrayList<Section>());
        }
        for(Section section : selectedSections) {
            newOrModifiedTeamBean.getSections().add(section);
        }
    }

    public List<Section> getAssignableSections() {
        if (assignableSections == null) {
            if (StringUtils.isNotEmpty(sectionNameFilter)) {
                this.assignableSections = new ArrayList<Section>();
                for(Section section : getSections()) {
                    if (section.getSectionName().toLowerCase().contains(sectionNameFilter.toLowerCase()) || section.getSectionCode().toLowerCase().contains(sectionNameFilter.toLowerCase())) {
                        assignableSections.add(section);
                    }
                }
            } else {
                this.assignableSections = getSections();
            }
        }
        if (newOrModifiedTeamBean.getSections() != null && !newOrModifiedTeamBean.getSections().isEmpty()) {
            List<Section> subtractionList = new ArrayList<Section>(assignableSections);
            Iterator<Section> iterator = newOrModifiedTeamBean.getSections().iterator();
            while (iterator.hasNext()) {
                subtractionList.remove(iterator.next());
            }
            return subtractionList;
        }
        return assignableSections;
    }

    public void setAssignableSections(List<Section> assignableSections) {
        this.assignableSections = assignableSections;
    }

    public List<Section> getSections() {
        if (sections == null) {
            this.sections = sectionService.findAll();
        }
        return sections;
    }

    public String getSectionNameFilter() {
        return sectionNameFilter;
    }

    public void setSectionNameFilter(String sectionNameFilter) {
        this.sectionNameFilter = sectionNameFilter;
        this.assignableSections = null;
    }

    public String getSectionNameForSelectComponent(Long sectionId) {
        for(Section section : getAssignableSections()) {
            if (section.getSectionId().equals(sectionId)) {
                return section.getSectionName() + " (" + section.getSectionCode() +")";
            }
        }
        return null;
    }

    private List<User> getUsers() {
        if (users == null) {
            this.users = userService.findAll();
        }
        return users;
    }

    public List<UserMapper> getAssignableUsers() {
        if (assignableUsers == null) {
            this.assignableUsers = new ArrayList<UserMapper>();
            for(User user : getUsers()) {
                if (newOrModifiedTeamBean.getMembers() == null || !newOrModifiedTeamBean.getMembers().contains(user)) {
                    assignableUsers.add(new UserMapper(user));
                }
            }
        }
        return assignableUsers;
    }

    public void setAssignableUsers(List<UserMapper> assignableUsers) {
        this.assignableUsers = assignableUsers;
    }

    public List<UserMapper> getFilteredUsers() {
        return filteredUsers;
    }

    public void setFilteredUsers(List<UserMapper> filteredUsers) {
        this.filteredUsers = filteredUsers;
    }

    public boolean isSelectAllBox() {
        return selectAllBox;
    }

    public void setSelectAllBox(boolean selectAllBox) {
        this.selectAllBox = selectAllBox;
    }

    public void selectAll(boolean state){
        this.selectAllBox = state;
        for(UserMapper user : assignableUsers) {
            user.setChecked(selectAllBox);
        }
    }

    public List<User> getAssignedMembers() {
        return newOrModifiedTeamBean.getMembers();
    }

    public void assignSelectedUsers() {
        for(UserMapper userItem : getAssignableUsers()) {
            if (userItem.isChecked()) {
                if (newOrModifiedTeamBean.getMembers() == null) {
                    newOrModifiedTeamBean.setMembers(new ArrayList<User>());
                }
                newOrModifiedTeamBean.getMembers().add(userItem.getUser());
            }
        }
        setAssignableUsers(null);
    }

    public void removeAssignedMember(User member) {
        newOrModifiedTeamBean.getMembers().remove(member);
        setAssignableUsers(null);
    }

    public void removeAllMembers() {
        if (newOrModifiedTeamBean.getMembers() != null) {
            newOrModifiedTeamBean.getMembers().clear();
            setAssignableUsers(null);
        }
    }

    public String getTeamLeaderFullName(Team team) {
        if (team != null && team.getTeamLeader() != null) {
            return team.getTeamLeader().getFirstname() + " " + team.getTeamLeader().getLastname() + " (" + team.getTeamLeader().getUsername() + ")";
        }
        return null;
    }

    public String getAssignedSectionsAsString(List<Section> sections) {
        if (sections != null && !sections.isEmpty()) {
            StringBuilder sectionNames = new StringBuilder();
            for(Section section : sections) {
                sectionNames.append(section.getSectionName() + ", ");
            }
            return sectionNames.length() > 0 ? sectionNames.toString().substring(0, sectionNames.length()-2) : "no sections assigned";
        }
        return null;
    }

    public Converter getTeamLeaderConverter() {
        return new Converter() {
            @Override
            public Object getAsObject(FacesContext context, UIComponent component, String value) {
                for(User user : getAvailableUsers()) {
                    if (user.getUsername().equals(value)) {
                        return user;
                    }
                }
                return null;
            }

            @Override
            public String getAsString(FacesContext context, UIComponent component, Object value) {
                return value.toString();
            }
        };
    }

    public Converter getSectionConverter() {
        return new Converter() {
            @Override
            public Object getAsObject(FacesContext context, UIComponent component, String value) {
                for(Section section : getAssignableSections()) {
                    if (section.toString().equals(value)) {
                        return section;
                    }
                }
                return null;
            }

            @Override
            public String getAsString(FacesContext context, UIComponent component, Object value) {
                return value.toString();
            }
        };
    }
}